package com.example.wl.tiaoyinqi;

import android.Manifest;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.wl.tiaoyinqi.audio.AudioProcess;
import com.example.wl.tiaoyinqi.yueqifragments.GuitarFragment;
import com.example.wl.tiaoyinqi.yueqifragments.GuqinFragment;
import com.example.wl.tiaoyinqi.yueqifragments.GuzhengFragment;
import com.example.wl.tiaoyinqi.yueqifragments.Lyre15Fragment;
import com.example.wl.tiaoyinqi.yueqifragments.Lyre7Fragment;
import com.example.wl.tiaoyinqi.yueqifragments.PipaFragment;
import com.example.wl.tiaoyinqi.yueqifragments.ShouboqinFragment;

/**
 * Created by wl on 2016/5/23.
 */
public class MainActivity extends FragmentActivity implements
        MyCallbacks,
        View.OnClickListener {
    private float fre = 440.0f;
    private float prePos;
    private int xuanzhuandianY;
    private boolean isShiyin;
    private boolean isExact;

    private AudioProcess audioProcess;
    private RotateAnimation animation;
    private ShuomingDialog mShuomingDialog;
    private SelectDialog mSelectDialog;
    private FragmentManager fm;
    private TextView mTextView, mLetText, mNumText;
    private ImageView pointer;
    private Fragment guitarFragment, pipaFragment, guzhengFragment, shouboqinFragment,
            guqinFragment, lyre7Fragment, lyre15Fragment;
    private String lastShowFragmentTag;
    private int currentFragmentTagNum;
    private SoundPool mSoundPool;

    private int[] lastShowXian = new int[]{
            -1, -1, -1, -1, -1, -1, -1
    };

    private static final double RATE_40 = 1.02337391;       //40音分相差倍数（每半音相差100音分）
    private static final double RATE_20 = 1.01161945;       //20音分相差倍数
    private static final double RATE = 1.0594630943592953;  //每半音相差倍数

    public static final int TAG_NUM_guitar = 0;
    public static final int TAG_NUM_shouboqin = 1;
    public static final int TAG_NUM_lyre7 = 2;
    public static final int TAG_NUM_lyre15 = 3;
    public static final int TAG_NUM_guzheng = 4;
    public static final int TAG_NUM_guqin = 5;
    public static final int TAG_NUM_pipa = 6;

    private final String LAST_SHOW_FRAGMENT = "last";
    private final String TAG_shuomingDialog = "shuoming";
    private final String TAG_selectDialog = "select";
    private final String[] TAGs = new String[]{
            "guitar", "shouboqin", "lyre7", "lyre15",
            "guzheng", "guqin", "pipa"
    };

    //音符
    private final String[] STR_LET = new String[]{
            "C", "♯C", "D", "♯D", "E", "F", "♯F", "G", "♯G", "A", "♯A", "B"
    };

    //各乐器各参照弦音符
    private final int[][] num_first_letter = new int[][]{
            {4,4}, {0, 4, 7}, {2, 2}, {7,4,0}, {2, 2, 2, 2, 2}, {0,0}, {9}
    };

    //各参照弦音符下标数字
    private final int[][] first_num = new int[][]{
            {2,4}, {6, 5, 4}, {4, 5}, {3,4,5}, {2, 3, 4, 5, 6}, {2,3}, {3}
    };

    //各参照弦所参照的mid音频文件id
    private final int[][] midPath = new int[][]{
            {R.raw.e2_82,R.raw.c4_262},
            {R.raw.g5sheng_831, R.raw.d5sheng_622, R.raw.f4_349},
            {R.raw.c4_262, R.raw.a4sheng_466},
            {R.raw.g3_196,R.raw.c4_262,R.raw.a4sheng_466},
            {R.raw.b1_62, R.raw.d3_147, R.raw.c4_262, R.raw.a4sheng_466, R.raw.m0_85},
            {R.raw.b1_62,R.raw.a2_110},
            {R.raw.g3_196}
    };

    //各乐器各参照弦弦与mid音频相差半音数
    private final int[][] num_first = new int[][]{
            {0,4}, {4, 1, 2}, {2, 4}, {0,4,2}, {3, 0, 2, 4, 1}, {1,3}, {2}
    };

    //各乐器各弦相对参照弦相差半音数,为0的即为参照弦
    private final int[][] num_xians = new int[][]{
            {0, 5, 10, 15, 19, 0},
            {7, 5, 4, 2, 0, 7, 5, 3, 1, 0, 7, 5, 4, 2, 0},
            {0, 2, 5, 7, 9, 0, 2},
            {0, 2, 4, 5, 7, 0, 1, 3, 5, 7, 0, 2, 4, 5, 7},
            {0, 2, 4, 7, 9, 0, 2, 4, 7, 9, 0, 2, 4, 7, 9, 0, 2, 4, 7, 9, 0},
            {0, 2, 5, 7, 9, 0, 2},
            {0, 5, 7, 12}
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        isShiyin = false;

        fm = getSupportFragmentManager();

        if (savedInstanceState != null) {
            guitarFragment = fm.findFragmentByTag(TAGs[TAG_NUM_guitar]);
            pipaFragment = fm.findFragmentByTag(TAGs[TAG_NUM_pipa]);
            guzhengFragment = fm.findFragmentByTag(TAGs[TAG_NUM_guzheng]);
            shouboqinFragment = fm.findFragmentByTag(TAGs[TAG_NUM_shouboqin]);
            guqinFragment = fm.findFragmentByTag(TAGs[TAG_NUM_guqin]);
            lyre7Fragment = fm.findFragmentByTag(TAGs[TAG_NUM_lyre7]);
            lyre15Fragment = fm.findFragmentByTag(TAGs[TAG_NUM_lyre15]);

            lastShowFragmentTag = savedInstanceState.getString(LAST_SHOW_FRAGMENT);

            fm.beginTransaction()
                    .hide(guitarFragment)
                    .hide(pipaFragment)
                    .hide(guzhengFragment)
                    .hide(shouboqinFragment)
                    .hide(lyre7Fragment)
                    .hide(lyre15Fragment)
                    .show(fm.findFragmentByTag(lastShowFragmentTag))
                    .commit();

        } else {
            guitarFragment = new GuitarFragment();
            pipaFragment = new PipaFragment();
            guzhengFragment = new GuzhengFragment();
            shouboqinFragment = new ShouboqinFragment();
            guqinFragment = new GuqinFragment();
            lyre7Fragment = new Lyre7Fragment();
            lyre15Fragment = new Lyre15Fragment();

            if (fm.findFragmentById(R.id.fragment_container) == null) {
                fm.beginTransaction()
                        .add(R.id.fragment_container, guitarFragment, TAGs[TAG_NUM_guitar])
                        .add(R.id.fragment_container, pipaFragment, TAGs[TAG_NUM_pipa])
                        .add(R.id.fragment_container, guzhengFragment, TAGs[TAG_NUM_guzheng])
                        .add(R.id.fragment_container, shouboqinFragment, TAGs[TAG_NUM_shouboqin])
                        .add(R.id.fragment_container, guqinFragment, TAGs[TAG_NUM_guqin])
                        .add(R.id.fragment_container, lyre7Fragment, TAGs[TAG_NUM_lyre7])
                        .add(R.id.fragment_container, lyre15Fragment, TAGs[TAG_NUM_lyre15])
                        .hide(lyre15Fragment)
                        .hide(lyre7Fragment)
                        .hide(guzhengFragment)
                        .hide(pipaFragment)
                        .hide(shouboqinFragment)
                        .hide(guqinFragment)
                        .commit();
            }

            lastShowFragmentTag = TAGs[TAG_NUM_guitar];
        }

        int[] imageButtonIds = new int[]{
                R.id.activity_btn_back,
                R.id.activity_btn_help,
                R.id.activity_btn_change
        };

        for (int imageButtonId : imageButtonIds) {
            ImageButton imageButton = (ImageButton) findViewById(imageButtonId);
            imageButton.setOnClickListener(this);
        }

        mTextView = (TextView) findViewById(R.id.activity_textView);
        mLetText = (TextView) findViewById(R.id.activity_textView_big);
        mNumText = (TextView) findViewById(R.id.activity_textView_small);
        pointer = (ImageView) findViewById(R.id.pointer);
        ViewGroup.MarginLayoutParams mLayoutParams =
                (ViewGroup.MarginLayoutParams) pointer.getLayoutParams();
        xuanzhuandianY = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 52,
                getResources().getDisplayMetrics()) + mLayoutParams.height / 2;

        SharedPreferences mSharedPreferences = getSharedPreferences("isFirst", MODE_PRIVATE);
        SharedPreferences.Editor editor = mSharedPreferences.edit();

        mShuomingDialog = new ShuomingDialog();
        mSelectDialog = new SelectDialog();

        mSelectDialog.show(fm, TAG_selectDialog);
        if (mSharedPreferences.getInt("isFirst", 1) == 1) {
            mShuomingDialog.show(fm, TAG_shuomingDialog);
            editor.putInt("isFirst", 0);
            editor.apply();
        }

    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(LAST_SHOW_FRAGMENT, lastShowFragmentTag);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (isShiyin) {
            startShiyin();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (isShiyin) {
            stopShiyin();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mSoundPool != null) {
            mSoundPool.release();
            mSoundPool = null;
        }
    }

    @Override
    public void onShuomingButtonOffClick() {
        mShuomingDialog.dismiss();
    }

    @Override
    public void onYueqiSelect(View v) {
        switch (v.getId()) {
            case R.id.btn_guitar:
                mTextView.setText(getString(R.string.guitar));
                currentFragmentTagNum = TAG_NUM_guitar;
                showFragment(guitarFragment);
                break;
            case R.id.btn_shouboqin:
                mTextView.setText(getString(R.string.shouboqin));
                currentFragmentTagNum = TAG_NUM_shouboqin;
                showFragment(shouboqinFragment);
                break;
            case R.id.btn_lyre7:
                mTextView.setText(getString(R.string.lyre7));
                currentFragmentTagNum = TAG_NUM_lyre7;
                showFragment(lyre7Fragment);
                break;
            case R.id.btn_lyre15:
                mTextView.setText(getString(R.string.lyre15));
                currentFragmentTagNum = TAG_NUM_lyre15;
                showFragment(lyre15Fragment);
                break;
            case R.id.btn_guzheng:
                mTextView.setText(getString(R.string.guzheng));
                currentFragmentTagNum = TAG_NUM_guzheng;
                showFragment(guzhengFragment);
                break;
            case R.id.btn_guqin:
                mTextView.setText(getString(R.string.guqin));
                currentFragmentTagNum = TAG_NUM_guqin;
                showFragment(guqinFragment);
                break;
            case R.id.btn_pipa:
                mTextView.setText(getString(R.string.pipa));
                currentFragmentTagNum = TAG_NUM_pipa;
                showFragment(pipaFragment);
                break;
            default:
                break;
        }
    }

    @Override
    public void onXianClick(int position) {

        lastShowXian[currentFragmentTagNum] = position;

        if (!hasRecordingPermission()) {
            return;
        }
        int i = 0;
        if (currentFragmentTagNum != TAG_NUM_pipa) {
            i = position / 5;
        }
        loadBiaoZhunYin(i, position);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.activity_btn_back:
                finish();
                break;
            case R.id.activity_btn_help:
                mShuomingDialog.show(fm, TAG_shuomingDialog);
                break;
            default:
                mSelectDialog.show(fm, TAG_selectDialog);
                break;
        }
    }

    private void showFragment(Fragment f) {
        if (mSoundPool != null) {
            mSoundPool.release();
            mSoundPool = null;
        }
        mSoundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);

        if (lastShowXian[currentFragmentTagNum] != -1) {
            int i = 0;
            if (currentFragmentTagNum != TAG_NUM_pipa) {
                i = lastShowXian[currentFragmentTagNum] / 5;
            }
            setNoteText(i);

            if (!isShiyin) {
                startShiyin();
                isShiyin = true;
            }
        } else {
            if (isShiyin) {
                stopShiyin();
                resetPointer();
                isShiyin = false;
            }
        }
        if (!f.isVisible()) {
            fm.beginTransaction()
                    .hide(fm.findFragmentByTag(lastShowFragmentTag))
                    .show(f)
                    .commit();
            lastShowFragmentTag = f.getTag();
        }
        mSelectDialog.dismiss();

    }

    private void loadBiaoZhunYin(final int i, final int position) {
        setNoteText(i);
        if (!isShiyin) {
            startShiyin();
            isShiyin = true;
        }
        mSoundPool.load(this, midPath[currentFragmentTagNum][i], 1);
        mSoundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
            @Override
            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                mSoundPool.play(sampleId, 1, 1, 0, 0,
                        (float) Math.pow(RATE,
                                (num_first[currentFragmentTagNum][i] +
                                        num_xians[currentFragmentTagNum][position])));
            }
        });
    }

    private void setNoteText(int i) {
        int num = num_first_letter[currentFragmentTagNum][i] +
                num_xians[currentFragmentTagNum][lastShowXian[currentFragmentTagNum]];
        mLetText.setText(STR_LET[num % 12]);
        mNumText.setText(String.valueOf(num / 12 + first_num[currentFragmentTagNum][i]));
        double j = 12 * (num / 12 + first_num[currentFragmentTagNum][i] - 4) + (num % 12 - 9);
        fre = (float) (Math.pow(RATE, j) * 440);
        //j为当前音阶与标准音A4相差的半音数(j = 12 * 下标相差 + 字符相差)
    }

    private void makeAnimation(float pos) {
        animation = new RotateAnimation(prePos, pos, Animation.RELATIVE_TO_SELF, 0.5f, Animation.ABSOLUTE, xuanzhuandianY);
        animation.setDuration(200);
        animation.setFillAfter(true);
        animation.setInterpolator(new AccelerateDecelerateInterpolator());
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                pointer.startAnimation(animation);
                if (!isExact) {
                    pointer.setBackgroundResource(R.drawable.pic_pointer2);
                } else {
                    pointer.setBackgroundResource(R.drawable.pic_pointer);
                }

            }
        });
        prePos = pos;
    }

    private void stopShiyin() {
        if (audioProcess != null) {
            audioProcess.stop();
        }
        if (animation != null) {
            animation.cancel();
        }
    }

    private void resetPointer() {
        animation = new RotateAnimation(prePos, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.ABSOLUTE, xuanzhuandianY);
        animation.setDuration(200);
        animation.setFillAfter(true);
        animation.setInterpolator(new AccelerateDecelerateInterpolator());
        pointer.startAnimation(animation);
        pointer.setBackgroundResource(R.drawable.pic_pointer);
        prePos = 0;
        isExact = true;
    }

    private void startShiyin() {
        audioProcess = new AudioProcess();
        audioProcess.setOnFreqChangedListener(new AudioProcess.OnFreqChangedListener() {
            @Override
            public void onFreqChanged(float freq) {
                isExact = freq > fre / RATE_20 && freq < fre * RATE_20;    //音是否准确

                float degree;
                if (freq < fre / RATE_40) {
                    degree = -56;
                    Log.d("MainActivity", "频率为" + freq + "，太小，中心频率为" + fre);
                } else if (freq > fre * RATE_40) {
                    degree = 56;
                    Log.d("MainActivity", "频率为" + freq + "，太大" + "，中心频率为" + fre);
                } else {
                    degree = (float) (56 * (freq - fre) / (fre * RATE_40 - fre / RATE_40));
                    Log.d("MainActivity", "频率为" + freq + ", 偏移度数为" + degree + "，中心频率为" + fre);
                }
                makeAnimation(degree);
            }
        });
        audioProcess.start();
    }

    private boolean hasRecordingPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 0);
                return false;
            }
        }
        return true;
    }
}
